package cc.telecomdigital.tdstock.Tools;

import java.util.Timer;
import java.util.TimerTask;

import cc.telecomdigital.tdstock.Framework.UniqueItem.TDStockLog;

/** A timer has the ability to report remaining time in resolution of second
 *  also allow to extend the timer in second
 */
public class ReporterTicker
{
	private static final boolean debugMode  = false;

	public interface IReporterTicker_Report
	{
		void ReporterTicker_Response(int iRemainSecond);
	}

	private static final String  LOG_TAG  = "ReporterTicker";
	private static final int     timerMaxSecondValue   = 2174783;   /* Calculate by a factor */
	private static final int     ONE_SECOND = 1000;

	//Pad Lock during the Timer process
	private final Object padLock = new Object();	
	
	// Store whether the internal timer started
	private boolean hasStarted;
	// The running start of the timer
	private boolean isRunning;
	// The remaining timeout for internal timer
	private int remainTick;	
	// The timer that it has increment before

	/** Timer for the second change **/
	private Timer     secondTimer;
	/** Timer task when it reached */
	private TimerTask secondTask;

	/** To export result to out side */
	private IReporterTicker_Report  reporter;

	/** Introduce a changeable timer and report the timer on each fraction of 10 second
	 *  if no reporter is used or iInitialiSecon is set, a throw exception will be used.
	 *  The timer will not start until it is said to be started
	 * @param iReporter    - iReporter, a call back for each 10 second
	 * @param iInitialTime - time in Second
	 * @throws Exception */
	public ReporterTicker(IReporterTicker_Report iReporter, int iSecond) throws Exception
	{
		if (iSecond > timerMaxSecondValue)
			throw new Exception("ReporterTicker: iSecond over the maximum");

		if (iReporter == null)
			throw new Exception("ReporterTicker: export function not found");

		hasStarted  = false;
		isRunning   = false;
		reporter    = iReporter;
		remainTick  = iSecond;

		//Max second to be set
		secondTimer  = new Timer();
		//A second Ticker Timer Task
		secondTask = CreateTimerTask();
	}

	/** Reset the Task, user requires to call start
	 *  to start the timer again **/
	public void Reset(int iSecond) throws Exception
	{
		if (iSecond > timerMaxSecondValue)
			throw new Exception("ReporterTicker: iSecond over the maximum at Reset");

		Stop();
		secondTask = CreateTimerTask();
		remainTick = iSecond * 60;
		isRunning = false;
		hasStarted = false;
	}

	private TimerTask CreateTimerTask()
	{
		TimerTask aOneSecondTask;

		aOneSecondTask = new TimerTask()
		{
			public void run()
			{
				synchronized(padLock)
				{
					--remainTick;

//					if (debugMode)
//					{
//						if (remainTick%5 == 0)
//							Log.i(LOG_TAG, "Remain Tick:" + remainTick);
//					}
					
					try
					{
						reporter.ReporterTicker_Response(remainTick);
						if (remainTick == 0)
							Stop();
					}
					catch(Exception eX)
					{
						TDStockLog.e(LOG_TAG, "TimerTask " + eX.toString());
					}
				}
			}
		};

		return aOneSecondTask;
	}

	/** Check whether the timer could still be used **/
	public boolean IsTimerValid()
	{
		synchronized(padLock)
		{
			if (secondTimer == null)
				return false;
			
			return true;
		}
	}

	/** Get the Remaining Second for the timer **/
	public int GetRemainingSecond()
	{
		synchronized(padLock)
		{
			return remainTick;
		}
	}

	/** Add Extra Minute to the timer
	 *  @param iPurchaseMinute - Purchase time in second
	 */
	public synchronized boolean IncrementInSecond(int iExtraSecond)
	{
		synchronized(padLock)
		{
			if (remainTick + iExtraSecond > timerMaxSecondValue)
				return false;

			remainTick += iExtraSecond;

			if (debugMode)
				TDStockLog.i(LOG_TAG, "Second Purchase " + String.valueOf(iExtraSecond) + ". Total Remain: " + remainTick);			
		}
		return true;
	}

	/** Tell whether the timer has been started or used **/
	public boolean IsStarted()
	{
		return hasStarted;
	}

	/** Provide information whether the timer is running **/
	public boolean IsRunning()
	{
		return isRunning;
	}

	/** Start the timer if it has not been started **/
	public void Start()
	{
		if (hasStarted == true)
			return;

		//Nothing to remain
		if (remainTick == 0)
		{
			if (debugMode)
				TDStockLog.i(LOG_TAG, "Start: Contain no purhcase second to started");
			return;
		}

		hasStarted = true;
		isRunning  = true;
		secondTimer.schedule(secondTask, ONE_SECOND, ONE_SECOND);
		/* Report once to user */
		reporter.ReporterTicker_Response(remainTick);
		if (debugMode)
			TDStockLog.i(LOG_TAG, "Start: TimerStart");
	}

	/** The Timer has been stopped, but can not be restarted **/
	public void Stop()
	{
		isRunning = false;
		/* Kill an clean up the timer */
		try
		{
			synchronized(padLock)
			{
				if (secondTimer != null)
				{
					secondTimer.cancel();
					secondTimer.purge();
					secondTimer = null;
				}
			}
		}
		catch(Exception ex)
		{
			TDStockLog.e(LOG_TAG, "Stop: " + ex.toString());
		}

		if (debugMode)
			TDStockLog.i(LOG_TAG, "Stop: The Timer has been stopped");				
	}

	/** Kill the Timer and kill the task **/
	public void Dispose()
	{
		Stop();
		try
		{
			synchronized(padLock)
			{
				if (secondTask != null)
				{
					secondTask.cancel();
					secondTask = null;
				}
			}
		}
		catch(Exception ex)
		{
			TDStockLog.e(LOG_TAG, "Dispose: " + ex.toString());
		}
		remainTick = 0;
		reporter = null;
		if (debugMode)
			TDStockLog.i(LOG_TAG, "Object has been destroyed.");		
	}
}
